package main

import (
	"fmt"
	"strconv"
	"strings"
	"time"
)

type TaskTemplate struct {
	Template string
}

func (_this *TaskTemplate) GetNextGroup() *GuessTask {
	// TODO 获得下一次待处理的内容，用于分组的管理
	return nil
}

type GuessTask struct {
	Concurrency int
	Template    string
	Salt        string
	PassStr     string

	StartTime  time.Time
	TaskChan   chan int
	CheckCount int64
	DealFinish bool
	Result     string
}

func NewGuessTask(concurrency int, template, salt, passStr string) *GuessTask {
	task := &GuessTask{
		Concurrency: concurrency,
		Template:    template,
		Salt:        salt,
		PassStr:     passStr,
	}

	task.StartTime = time.Now()
	task.TaskChan = make(chan int, task.Concurrency)

	return task
}

func (_this *GuessTask) IsFinished() bool {
	return (len(_this.TaskChan) == 0 && _this.DealFinish) || _this.Result != ""
}

func (_this *GuessTask) Deal() {
	_this.deal(_this.Template)
	_this.DealFinish = true
}

func (_this *GuessTask) deal(subTemplate string) {
	// 处理当前分组的所有内容，成功的话返回解析的内容，失败的话返回空

	pos1 := strings.Index(subTemplate, "{{")
	pos2 := strings.Index(subTemplate, "}}")
	if pos1 < 0 || pos2 < pos1 {
		go _this.checkOne(subTemplate)
		return
	}

	prefix := subTemplate[:pos1]
	modeStr := subTemplate[pos1+2 : pos2]
	suffix := subTemplate[pos2+2:]
	hasNumber := false
	hasLittleChar := false
	hasBigChar := false
	hasSymbol := false
	minLen := 0
	maxLen := 0
	modeHead := ""
	for i, c := range modeStr {
		if c == 'd' {
			hasNumber = true
		} else if c == 'c' {
			hasLittleChar = true
		} else if c == 'C' {
			hasBigChar = true
		} else if c == 'm' {
			hasSymbol = true
		} else if c >= '0' && c <= '9' {
			lenStr := modeStr[i:]
			modeHead = modeStr[:i]
			pos := strings.Index(lenStr, "-")
			if pos > 0 {
				str1 := lenStr[:pos]
				str2 := lenStr[pos+1:]
				minLen, _ = strconv.Atoi(str1)
				maxLen, _ = strconv.Atoi(str2)
			} else {
				minLen, _ = strconv.Atoi(lenStr)
				maxLen = minLen
			}
			break
		}
	}
	if minLen > 0 && maxLen > 3 {
		newSubTemplate := fmt.Sprintf("%s{{%s1}}{{%s%d-%d}}%s", prefix, modeHead, modeHead, minLen-1, maxLen-1, suffix)
		_this.deal(newSubTemplate)
		return
	}

	// 按照复杂度的规则重建此段密码生成逻辑
	for i := minLen; i <= maxLen; i++ {
		_this.dealStep("", 0, i, prefix, suffix, hasNumber, hasLittleChar, hasBigChar, hasSymbol)
	}
}

func (_this *GuessTask) dealStep(str string, j, i int, prefix, suffix string, hasNumber, hasLittleChar, hasBigChar, hasSymbol bool) {
	if hasNumber {
		if j < i {
			for k := 0; k < 10; k++ {
				_this.dealStep(str+fmt.Sprintf("%d", k), j+1, i, prefix, suffix, hasNumber, hasLittleChar, hasBigChar, hasSymbol)
			}
		} else {
			newSubTemplate := fmt.Sprintf("%s%s%s", prefix, str, suffix)
			_this.deal(newSubTemplate)
		}
	}
}

func (_this *GuessTask) checkOne(onePass string) {
	_this.TaskChan <- 1
	defer func() {
		<-_this.TaskChan
	}()

	ok, err := CheckCrypt(onePass, _this.Salt, _this.PassStr)
	if err != nil {
		fmt.Println(err.Error())
	}
	_this.CheckCount++
	if _this.CheckCount%10000 == 0 {
		fmt.Printf("  已破解密码个数：%v，总耗时：%v\n", _this.CheckCount, time.Since(_this.StartTime).String())
	}
	if ok {
		_this.Result = onePass
	}
}
